package main

import (
	"LocalPort2Lucky/platform"
	"LocalPort2Lucky/portforward"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	sysruntime "runtime"
	"sync"
	"time"

	"github.com/wailsapp/wails/v2/pkg/runtime"
)

// App 结构体定义
type App struct {
	ctx       context.Context
	cmd       *exec.Cmd
	isRunning bool
	proxyList []ProxyStatus
	mu        sync.RWMutex // 添加互斥锁
	pidFile   string       // PID文件路径
	pf        *portforward.PortForwarder
}

// Config 配置结构体
type Config struct {
	APIURL   string     `json:"API_URL"`
	RuleInfo []RuleInfo `json:"ruleInfo"`
	// GostPathWindows string     `json:"gost_path_windows"`
	// GostPathUnix    string     `json:"gost_path_unix"`
}

// RuleInfo 规则信息结构体
type RuleInfo struct {
	RuleName  string `json:"ruleName"`
	HomeAddr  string `json:"homeAddr"`
	NetWork   string `json:"network"`
	LocalPort int    `json:"localport"`
}

// ApiResponse API响应结构体
type ApiResponse struct {
	RuleName string `json:"ruleName"`
	HomeAddr string `json:"homeAddr"`
	IPAddr   string `json:"ipAddr"`
}

// ProxyStatus 代理状态结构体
type ProxyStatus struct {
	RuleName  string `json:"ruleName"`
	LocalPort int    `json:"localport"`
}

// NewApp 创建新的App实例
func NewApp() *App {
	execPath, _ := os.Executable()
	pidFile := filepath.Join(filepath.Dir(execPath), "proxy.pid")

	return &App{
		proxyList: make([]ProxyStatus, 0),
		pidFile:   pidFile,
	}
}

// Startup 启动函数
func (a *App) Startup(ctx context.Context) {
	a.ctx = ctx
	// 创建端口转发器实例
	a.pf = portforward.NewPortForwarder(portforward.DefaultConfig(), nil)
}

func EnsureFileExists(filePath string) error {
	// 检查文件是否存在
	if _, err := os.Stat(filePath); err == nil {
		fmt.Println("文件已存在：", filePath)
		return nil
	} else if !os.IsNotExist(err) {
		// 返回其他错误
		return fmt.Errorf("检查文件时出错: %w", err)
	}

	// 文件不存在，创建并写入内容
	defaultContent := Config{
		APIURL: "https://aliyun.281898533.icu/luckyapi/logs",
		RuleInfo: []RuleInfo{
			{
				RuleName:  "RuleName1",
				HomeAddr:  "home901",
				LocalPort: 8070,
				NetWork:   "tcp",
			},
			{
				RuleName:  "RuleName2",
				HomeAddr:  "home901",
				LocalPort: 8072,
				NetWork:   "udp",
			},
		},
	}

	// 转换为JSON
	jsonData, err := json.MarshalIndent(defaultContent, "", "  ")
	if err != nil {
		return fmt.Errorf("序列化默认内容时出错: %w", err)
	}

	// 写入文件
	if err := ioutil.WriteFile(filePath, jsonData, 0644); err != nil {
		return fmt.Errorf("写入文件时出错: %w", err)
	}

	fmt.Println("文件已创建并写入默认内容：", filePath)
	return nil
}

// LoadConfig 加载配置
func (a *App) LoadConfig() (*Config, error) {
	execPath, err := os.Executable()
	if err != nil {
		return nil, fmt.Errorf("get executable path failed: %v", err)
	}

	configPath := filepath.Join(filepath.Dir(execPath), "config.json")
	EnsureFileExists(configPath) //文件不存在则新增默认
	data, err := os.ReadFile(configPath)
	if err != nil {
		return nil, fmt.Errorf("read config file failed: %v", err)
	}

	var config Config
	if err := json.Unmarshal(data, &config); err != nil {
		return nil, fmt.Errorf("parse config file failed: %v", err)
	}

	return &config, nil
}

// FetchData 获取API数据
func (a *App) FetchData(apiURL string) ([]ApiResponse, error) {
	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	resp, err := client.Get(apiURL)
	if err != nil {
		return nil, fmt.Errorf("fetch data failed: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response failed: %v", err)
	}

	var apiResponse []ApiResponse
	if err := json.Unmarshal(body, &apiResponse); err != nil {
		return nil, fmt.Errorf("parse API response failed: %v", err)
	}

	return apiResponse, nil
}

// FilterData 过滤数据
func (a *App) FilterData(data []ApiResponse, ruleName, homeAddr string) string {
	for _, item := range data {
		if item.RuleName == ruleName && item.HomeAddr == homeAddr {
			return item.IPAddr
		}
	}
	return ""
}

// StartProxy 启动代理
func (a *App) StartProxy() (string, error) {
	a.mu.Lock()
	defer a.mu.Unlock()

	if a.isRunning {
		return "", fmt.Errorf("proxy is already running")
	}

	config, err := a.LoadConfig()
	if err != nil {
		return "", fmt.Errorf("load config failed: %v", err)
	}

	data, err := a.FetchData(config.APIURL)
	if err != nil {
		return "", fmt.Errorf("fetch data failed: %v", err)
	}

	args := make([]string, 0)
	a.proxyList = make([]ProxyStatus, 0)

	for _, rule := range config.RuleInfo {
		ipAddr := a.FilterData(data, rule.RuleName, rule.HomeAddr)
		if ipAddr != "" {
			args = append(args, fmt.Sprintf("-L=tcp://:%d/%s", rule.LocalPort, ipAddr))

			if rule.NetWork == "tcp" {
				err = a.pf.StartTCPProxy(fmt.Sprintf("0.0.0.0:%d", rule.LocalPort), ipAddr)
				if err != nil {
					a.pf.StopForwarding("all")
					return "", fmt.Errorf(" %v", err)
				}
			}
			if rule.NetWork == "udp" {
				err = a.pf.StartUDPProxy(fmt.Sprintf("0.0.0.0:%d", rule.LocalPort), ipAddr)
				if err != nil {
					a.pf.StopForwarding("all")
					return "", fmt.Errorf(" %v", err)
				}
			}

			a.proxyList = append(a.proxyList, ProxyStatus{
				RuleName:  rule.RuleName,
				LocalPort: rule.LocalPort,
			})
		}
	}

	if len(args) == 0 {
		return "", fmt.Errorf("no valid proxy rules found")
	}

	a.isRunning = true
	return "proxy started successfully", nil
}
func (a *App) AlertMsgbox(msg string) (string, error) {
	result, err := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
		Type:          runtime.QuestionDialog,
		Title:         "提示",
		Message:       msg,
		DefaultButton: "No",
	})
	return result, err
}

// StopProxy 停止代理
func (a *App) StopProxy() (string, error) {
	a.mu.Lock()
	defer a.mu.Unlock()
	a.pf.StopForwarding("all")
	a.pf.Wait() // 等待进程确实终止
	a.isRunning = false
	a.cmd = nil
	a.proxyList = make([]ProxyStatus, 0)
	return "proxy stopped", nil
}

// GetProxyStatus 获取代理状态
func (a *App) GetProxyStatus() map[string]interface{} {
	a.mu.RLock()
	defer a.mu.RUnlock()

	status := map[string]interface{}{
		"isRunning": a.isRunning,
		"proxyList": a.proxyList,
	}

	return status
}

// OpenURLInDefaultBrowser 打开给定的URL在默认浏览器中
func (a *App) OpenURLInDefaultBrowser(port string) error {
	var cmd string
	var args []string
	switch sysruntime.GOOS {
	case "windows":
		cmd = "cmd"
		args = []string{"/c", "start"}
	case "darwin":
		cmd = "open"
	default: // "linux", "freebsd", "openbsd", "netbsd"
		cmd = "xdg-open"
	}
	url := url.URL{Scheme: "http", Host: "localhost:" + port}
	args = append(args, url.String())
	return platform.NewCommand(cmd, args...).Start()

}

func (a *App) EditConfig() error {
	execPath, err := os.Executable()
	if err != nil {
		return fmt.Errorf("get open config file failed: %v", err)
	}
	var cmd *exec.Cmd
	configPath := filepath.Join(filepath.Dir(execPath), "config.json")
	switch sysruntime.GOOS {
	case "windows":
		cmd = platform.NewCommand("cmd", "/c", "start", configPath)
	case "darwin": // macOS
		cmd = platform.NewCommand("open", configPath)
	default: // For Linux and other Unix-like systems
		cmd = platform.NewCommand("xdg-open", configPath)
	}
	return cmd.Start()

}
